/**
 * Created by lwei on 2017/4/21.
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var CipherSql = (function (_super) {
    __extends(CipherSql, _super);
    /**
     *
     * @param dbPath 数据库文件路径
     * @param pwd 数据库密码，没有密码则不加密数据库
     * @param algthm 加密算法，默认 'aes-256-ctr'
     */
    function CipherSql(dbPath, pwd, algthm) {
        var _this = this;
        algthm = algthm ? algthm : 'aes-256-ctr';
        if (!dbPath) {
            throw "必须指定数据库文件";
        }
        /**
         * 如果不存在数据库文件，创建数据库文件父路径
         */
        if (!CipherSql.fs.existsSync(dbPath)) {
            var dir = CipherSql.path.parse(dbPath).dir;
            CipherSql.mkdirs(dir);
            /*创建数据库文件*/
            CipherSql.fs.closeSync(CipherSql.fs.openSync(dbPath, 'w'));
        }
        var buffer, dbFile;
        try {
            buffer = CipherSql.fs.readFileSync(dbPath);
        }
        catch (e) {
            console.error(e.stack);
            throw "数据库文件错误";
        }
        if (pwd) {
            try {
                /*解密数据库文件*/
                var decipher = CipherSql.CryptoJS.createDecipher(algthm, pwd);
                buffer = Buffer.concat([decipher.update(buffer), decipher.final()]);
            }
            catch (e) {
                console.error(e.stack);
                throw "密码不正确 或者数据库未被加密 或者数据库文件已损坏";
            }
        }
        try {
            _this = _super.call(this, buffer) || this;
        }
        catch (e) {
            console.error(e.stack);
            if (pwd) {
                throw "数据库文件已损坏";
            }
            else {
                throw "数据库文件已被被加密或者数据库文件已损坏";
            }
        }
        /*测试数据库文件是否可用*/
        try {
            _this.exec('SELECT * FROM sqlite_master WHERE type = "table"');
            _this.dbPath = dbPath;
            _this.pwd = pwd;
            _this.algorithm = algthm;
            _this.dbFile = dbFile;
            /**
             * 创建临时数据库文件
             * @type {string}
             */
            _this.tempDb = _this.dbPath + ".temp";
            _this.tempFile = CipherSql.fs.openSync(_this.tempDb, 'w'); /*锁住文件*/
        }
        catch (e) {
            if (pwd) {
                throw "数据库文件已损坏";
            }
            else {
                throw "数据库文件已被被加密或者数据库文件已损坏";
            }
        }
        return _this;
    }
    /**
     * 数据库在内存中被改变之后，保存到银盘
     */
    CipherSql.prototype.save = function () {
        /*高版本node可以直接保存，低版本需要buffer*/
        var buffer = new Buffer(_super.prototype.export.call(this));
        /*加密之后保存*/
        if (this.pwd) {
            var cipher = CipherSql.CryptoJS.createCipher(this.algorithm, this.pwd);
            buffer = Buffer.concat([cipher.update(buffer), cipher.final()]);
        }
        /*先写到临时文件，再复制到正式数据库文件*/
        try {
            CipherSql.fs.writeFileSync(this.tempDb, buffer);
            CipherSql.fs.createReadStream(this.tempDb).pipe(CipherSql.fs.createWriteStream(this.dbPath));
        }
        catch (e) {
            console.error(e.stack);
        }
    };
    /**
     * Execute an SQL query, and returns the result.
     * @param sql
     * @returns {any}
     */
    CipherSql.prototype.exec = function (sql, params) {
        var result = null;
        if (!params) {
            var rset_1 = _super.prototype.exec.call(this, sql);
            /*将resultset 组装成object*/
            if (rset_1 && rset_1.length > 0) {
                result = [];
                rset_1 = rset_1[0];
                rset_1.values.forEach(function (t, i) {
                    var obj = {};
                    result.push(obj);
                    rset_1.columns.forEach(function (c, j) {
                        obj[c] = t[j];
                    });
                });
            }
        }
        else {
            var stam = _super.prototype.prepare.call(this, sql);
            stam.bind(params);
            while (stam.step()) {
                if (!result) {
                    result = [];
                }
                result.push(stam.getAsObject());
            }
        }
        return result;
    };
    /**
     * 释放文件锁，删除临时文件
     */
    CipherSql.prototype.close = function () {
        try {
            CipherSql.fs.closeSync(this.tempFile);
            /**
             * 删除临时文件
             */
            if (CipherSql.fs.existsSync(this.tempDb)) {
                CipherSql.fs.unlinkSync(this.tempDb);
            }
        }
        catch (e) {
            console.error(e.stack);
        }
        _super.prototype.close.call(this);
    };
    /**
     * 递归生成目录
     * @param dirpath
     */
    CipherSql.mkdirs = function (dirpath) {
        if (!CipherSql.fs.existsSync(dirpath)) {
            var p = CipherSql.path.parse(dirpath);
            var dir = p.dir;
            CipherSql.mkdirs(dir);
            CipherSql.fs.mkdirSync(dirpath);
            return;
        }
        return;
    };
    return CipherSql;
}(require('sql.js').Database));
CipherSql.fs = require('fs');
CipherSql.path = require("path");
CipherSql.CryptoJS = require("crypto"); /*加密库*/
